import React, { useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import { NavBar, Badge, Popover, Button, Dialog, SpinLoading } from "antd-mobile";
import { ChatAddOutline, CloseCircleOutline, UserSetOutline } from "antd-mobile-icons";
import { useLiveQuery } from "dexie-react-hooks";
import GroupChatCreator from "@/components/GroupChatCreator";
import GroupAvatar from "./GroupAvatar";
import { chatroom_list } from "@/apis";
import { currentDB } from "@/index";
import { convertMessage } from "@/utils";
import { connect, dispatch, getState, IStoreState } from "@/store";
import * as hm from "@/handle_message";
import styles from "./index.less";
import { __LOGOUT__, __ADMIN__ } from "@/common";

const _ChatList = (props: IStoreState) => {
  const { loginUser, userMap, chatrooms = [] } = props;
  const groupAvatarMap = new Map();
  const groupNameMap = new Map();
  const chats = [];
  for (const ele of chatrooms) {
    groupAvatarMap.set(
      ele._id,
      ele.users.map((u) => {
        const user = userMap.get(u.username);
        return user?.avatar;
      })
    );
    groupNameMap.set(ele._id, ele.name);
    chats.push(ele._id);
  }

  function reloadChatroomList() {
    chatroom_list({}).then(async (res) => {
      if (res.success) {
        dispatch(state => ({ ...state, chatrooms: res.data }))
        await currentDB.chatroom.clear();
        await currentDB.chatroom.bulkAdd(res.data);
      }
    });
  }

  useEffect(() => {
    reloadChatroomList();

    // todo: deal with separately
    hm.addEventListeners([
      "chatroom_create",
      "chatroom_delete",
      "chatroom_deluser",
      "chatroom_adduser",
    ], reloadChatroomList);

    return () => {
      // todo: deal with separately
      hm.removeEventListeners([
        "chatroom_create",
        "chatroom_delete",
        "chatroom_deluser",
        "chatroom_adduser",
      ], reloadChatroomList);
    };
  }, []);

  const chatList = useLiveQuery(() => currentDB.chatroom_last_message.orderBy("gmt_modified").filter(m => !m.hidden).reverse().toArray());
  const notSeenMap = useLiveQuery(async () => {
    const notSeenMap = new Map();

    await Promise.all(
      chats.map(async (chatroom_id) => {
        const seenCount = (await currentDB.seen_count.get({ chatroom_id }))?.seen_count || 0;
        const total = await currentDB.log.where({ chatroom_id }).count();
        const notSeen = total - seenCount;
        notSeenMap.set(chatroom_id, notSeen);

        return notSeen;
      })
    );

    return notSeenMap;
  }, [chats]);

  if (!chatList) return null; // Still loading.

  return (
    <>
      <NavBar
        className={styles["chat-list-header"]}
        back={null}
        right={
          <GroupChatCreator title="选择群成员">
            <ChatAddOutline fontSize={32} />
          </GroupChatCreator>
        }
        left={
          (__LOGOUT__ || __ADMIN__) ? (
            <Popover.Menu placement="bottom-start" trigger="click" actions={[
              __ADMIN__ && {
                key: __ADMIN__,
                icon: <UserSetOutline />,
                text: '个人信息'
              },
              __LOGOUT__ && {
                key: __LOGOUT__,
                icon: <CloseCircleOutline />,
                text: '退出登录'
              },
            ].filter(n => !!n)} onAction={act => {
              location.href = act.key as string
            }}>
              <UserSetOutline fontSize={32}/>
            </Popover.Menu>
          ) : null
        }
      >
        {loginUser.name}
      </NavBar>
      <div className={styles["group-list"]}>
        {chatList.map((chat) => {
          const groupAvatar = <GroupAvatar src={groupAvatarMap?.get(chat.chatroom_id as string)} />;
          const prefix = notSeenMap?.get(chat.chatroom_id) === 0 ? groupAvatar : <Badge content={notSeenMap?.get(chat.chatroom_id)}>{groupAvatar}</Badge>;

          return (
            <GroupListItem
              key={chat.chatroom_id as string}
              chatroom_id={chat.chatroom_id}
              prefix={prefix}
              groupName={groupNameMap?.get(chat.chatroom_id as string)}
              lastMessage={convertMessage(chat, userMap, loginUser)}
            />
          );
        })}
      </div>
    </>
  );
};

const ChatList = connect(getState)(_ChatList)
export default ChatList;

let touchInfo: { ts: number, x: number, y: number }
function GroupListItem(props) {
  const { prefix, groupName, lastMessage, chatroom_id } = props;
  const navigate = useNavigate();

  const events = (function () {
    const onTouchStart = function (e) {
      touchInfo = {
        ts: Date.now(),
        x: e.touches?.[0]?.screenX || 0,
        y: e.touches?.[0]?.screenY || 0,
      }
      const el = e.currentTarget as HTMLDivElement
      if (el.classList.contains(styles.focus)) {
        el.classList.remove(styles.focus)
      } else {
        el.classList.add(styles.focus)
      }
    }
    const onTouchMove = function (e) {
      if (touchInfo) {
        const y = e.touches?.[0]?.screenY || 0
        const el = e.currentTarget as HTMLDivElement
        if (Math.abs(y - touchInfo.y) > 20) {
          el.classList.remove(styles.focus)
          touchInfo = null
        }
      }
    }
    const onTouchEnd = function (e) {
      const el = e.currentTarget as HTMLDivElement
      const target = e.target as HTMLButtonElement
      if (target?.dataset?.type === 'del' && !el.classList.contains(styles.focus)) {
        Dialog.confirm({
          content: '确定删除群聊？',
          onConfirm: function () {
            currentDB.chatroom_last_message.update(chatroom_id, { hidden: true })
          }
        })
        touchInfo = null
      }

      if (!touchInfo) {
        return
      }
      const duration = Date.now() - touchInfo.ts
      if (duration > 2 && duration < 300 && el.classList.contains(styles.focus)) {
        navigate(`/chat_page/${chatroom_id}`);
      }
      touchInfo = null
    }
    return {
      onTouchStart,
      onTouchMove,
      onTouchEnd,
      onMouseDown: onTouchStart,
      onMouseUp: onTouchEnd,
    }
  })()

  const ref = useRef<HTMLDivElement>()
  useEffect(function () {
    const focus = function (e: MouseEvent) {
      if (ref.current) {
        if (!ref.current.contains(e.target as Node)) {
          ref.current.classList.remove(styles.focus)
        }
      }
    }
    document.addEventListener('click', focus)
    return function () {
      document.removeEventListener('click', focus)
    }
  }, [])

  return (
    <div className={styles["group-list-item"]} ref={ref} {...events}>
      <div className={styles["item-prefix"]}>{prefix}</div>
      <div className={styles["item-among"]}>
        <div className={styles["item-group-name"]}>{groupName || <SpinLoading style={{ '--size': '26px' }} />}</div>
        <div className={styles["item-group-last-message"]}>{lastMessage}</div>
      </div>
      <div className={styles['options']}>
        <Button color="danger" data-type="del">
          删除
        </Button>
      </div>
    </div>
  );
}
